package connection

import (
	"broker/interface/iserver"
	"broker/struct/router"
	"broker/utils"
	"broker/utils/logger"
	"fmt"
	"sync"
)

/*消息处理模块的实现*/

type MsgHandle struct {

	//消息队列
	TaskQueue []chan iserver.IRequest
	//worker工作池的数量
	WorkerPoolSize uint32
}

var msgHandle = &MsgHandle{}
var msgHandleOnce sync.Once
func NewMsgHandle() iserver.IMsgHandle {

	msgHandleOnce.Do(func() {
		msgHandle = &MsgHandle{
			TaskQueue:      make([]chan iserver.IRequest, utils.GetConfig().WorkerPoolSize),
			WorkerPoolSize: utils.GetConfig().WorkerPoolSize,
		}
	})
	return msgHandle

}

// DoMsgHandle 调度/执行对应的Router消息处理方法
func (mh *MsgHandle) DoMsgHandle(request iserver.IRequest) {
	//1.从路由表中找到handel
	handle, ok := request.GetConnection().GetTcpServer().GetRouters().GetRouter(request.GetMsgID())
	if !ok {
		logger.Info.Println("[MsgHandle] api msgID = ", request.GetMsgID(), "NOT FOUND!")
		errHandel := router.NewErrorRouter()
		errHandel.HandleByMessage(request, []byte(fmt.Sprintf("router msgID = %d NOT FOUND!", request.GetMsgID())))
		return
	}
	//2.根据msgID调用对应业务

	preRes := handle.PreHandle(request)
	if preRes != nil {
		handleRes := handle.Handle(request, preRes)
		if handleRes != nil {
			handle.PostHandle(request, handleRes)
		}
	}

}

// StartWorkPool 启动一个Worker工作池 (开启工作池的动作只能发生一次，一个框架只能有一个工作池)
func (mh *MsgHandle) StartWorkPool() {
	//根据workerPoolSize 分别开启worker 每个worker用一个go来承载
	for i := 0; i < int(mh.WorkerPoolSize); i++ {
		//一个worker被启动
		//1.当前的worker对应的channel消息队列 开辟空间 第0个worker 用第0个channel
		mh.TaskQueue[i] = make(chan iserver.IRequest, utils.GetConfig().MaxWorkerTaskSize)

		//2.启动当前worker 阻塞等待消息从channel传递进来
		go mh.startOneWorker(i, mh.TaskQueue[i])
	}
}

//启动一个Worker工作流程
func (mh *MsgHandle) startOneWorker(workID int, taskQueue chan iserver.IRequest) {
	//不断的阻塞等待对应消息队列的消息
	for {
		select {
		//如果有消息进来，出队的就是一个客户端的Request所绑定的业务
		case request := <-taskQueue:
			go mh.DoMsgHandle(request)
		}
	}
}

// SendMsgToTaskQueue 将消息交给TaskQueue由worker处理
func (mh *MsgHandle) SendMsgToTaskQueue(request iserver.IRequest) {
	//1.将消息平均分配给不同的worker
	//根据ConnID进行分配
	workerID := request.GetConnection().GetConnID() % mh.WorkerPoolSize
	logger.Info.Println("[MshHandle] add ConnID = ", request.GetConnection().GetConnID(), " request MsgID = ", request.GetMsgID(), " to WorkerID = ", workerID)
	//2.将消息发送给对应的worker的TaskQueue
	mh.TaskQueue[workerID] <- request
}
